<script setup lang="ts">
import type { SelectMixedOption, SelectOption } from 'naive-ui/es/select/src/interface'
import { h, computed, ref, type PropType, type VNodeChild, reactive, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { NTag } from 'naive-ui'
import { storeToRefs } from 'pinia'
import { ChannelShare28Regular, ChevronRight20Filled, Add20Regular } from '@vicons/fluent'
import { Icon } from '@vicons/utils'
import { emitter } from '@/utils/mitt'
import { useModelStore } from '@/stores/model'

const { t } = useI18n()

// 模型存储
const modelStore = useModelStore()
const { readUsableLlmModels, readUsableEmbedingModels } = storeToRefs(modelStore)

// 定义事件
const emits = defineEmits(['change'])

// 外部参数
const props = defineProps({
  // 模型类型
  type: {
    type: String as PropType<ModelType>,
    required: true,
  },
  // 是否显示设置
  showSetting: {
    type: Boolean,
    default: false,
  },
  // 是否使用PopSelect模式
  usePopselect: {
    type: Boolean,
    default: false,
  },
  // 未选占位符（仅非popselect模式）
  placeholder: {
    type: String,
  },
  // 是否可清除（仅非popselect模式）
  clearable: {
    type: Boolean,
    default: false,
  },
})

// 状态参数
const state = reactive({
  value: undefined,
})

// 组件
const selectRef = ref()

// 当前模型
const modelValue = defineModel('value', { type: String, required: true })

// 可选模型选项
const modelOptions = computed<SelectMixedOption[]>(() => {
  const options: SelectMixedOption[] = []
  const models = props.type === 'llm' ? readUsableLlmModels.value : readUsableEmbedingModels.value
  for (const model of models) {
    const child = {
      label: model.name,
      value: model.id,
      embedding: model.type === 'embedding',
      toolUse: !!model.toolUse,
      vision: !!model.vision,
    }
    let group = options.find((item) => item.value === model.supplier.id)
    if (!group) {
      group = {
        type: 'group',
        value: model.supplier.id,
        label: modelStore.getRealSupplierName(model.supplier.name),
        children: [child],
      }
      options.push(group)
    } else {
      ;(group.children as SelectOption[]).push(child)
    }
  }
  // 如果只有一个分组，直接返回该分组的 children
  if (options.length === 1 && (options[0] as any).children?.length) {
    return (options[0] as any).children
  }
  return options
})

// 选项渲染
const renderLabel = (option: SelectOption): VNodeChild => {
  const render: any[] = [option.label as string]
  if (option.embedding) {
    render.push(
      h(
        NTag,
        {
          type: 'warning',
          size: 'small',
          style: {
            cursor: 'pointer',
          },
        },
        {
          default: () => t('model.type.embedding'),
        },
      ),
    )
  }
  if (option.toolUse) {
    render.push(
      h(
        NTag,
        {
          type: 'primary',
          size: 'small',
          style: {
            cursor: 'pointer',
          },
        },
        {
          default: () => t('model.type.tool'),
        },
      ),
    )
  }
  if (option.vision) {
    render.push(
      h(
        NTag,
        {
          type: 'success',
          size: 'small',
          style: {
            cursor: 'pointer',
          },
        },
        {
          default: () => t('model.type.vision'),
        },
      ),
    )
  }
  return h('div', { style: { display: 'flex', alignItems: 'center', gap: '10px' } }, render)
}

// 设置
const onShowSetting = () => {
  selectRef.value.setShow(false)
  // 发送总线通知
  emitter.emit('onShowSettingModal', { tabName: 'supplier' })
}

// 切换模型
const onChangeModel = (key: string) => {
  modelValue.value = key || ''
  for (const group of modelOptions.value) {
    if (group.value === key) {
      emits('change', group)
      return
    }
    if (group.children) {
      for (const item of group.children as SelectOption[]) {
        if (item.value === key) {
          emits('change', item)
          return
        }
      }
    }
  }
}

// 用于解决placeholder不显示的问题
// select模式下，只有value为null或undefined时才会显示placeholder
watch(
  modelValue,
  (value) => {
    state.value = value || undefined
  },
  {
    immediate: true,
  },
)
</script>

<template>
  <n-popselect
    v-if="props.usePopselect"
    ref="selectRef"
    v-model:value="state.value"
    :options="modelOptions"
    trigger="click"
    scrollable
    :render-label="renderLabel"
    :on-update:value="onChangeModel"
  >
    <template v-if="props.showSetting" #action>
      <n-button size="small" type="default" text @click="onShowSetting">
        <template #icon>
          <Icon><Add20Regular /></Icon>
        </template>
        {{ t('model.addModel') }}
      </n-button>
    </template>
    <n-button :type="modelValue ? 'primary' : 'default'" secondary icon-placement="left">
      <template #icon>
        <Icon><ChannelShare28Regular /></Icon>
      </template>
      <span class="mr-1">{{ t('model.title') }}</span>
      <Icon><ChevronRight20Filled /></Icon>
    </n-button>
  </n-popselect>
  <n-select
    v-else
    ref="selectRef"
    v-model:value="state.value"
    :placeholder="props.placeholder || t('model.selectModel')"
    :options="modelOptions"
    :render-label="renderLabel"
    :clearable="props.clearable"
    :on-update:value="onChangeModel"
  />
</template>

<style lang="scss" scoped></style>
